[thirtyone~] 31 band 1/3 octave filter
Filters a signal using 31 evenly space 1/3 octave bandpass filters with gain, like a 31 band "graphic equalizer"

Inlet: signal
Outlet: filtered signal

Message: list of band number and decibel gain
Message: list of all 31 decibel gains
Message: reset

Arguments: list of 31 decibel gains

Frequency centers - starting at 20 Hz
Hz = Hz * 2 ^ (1/3)

Approximate centers:
   20   25 31.5   40   50   63   80   100   125   160
  200  250  315  400  500  630  800  1000  1250  1600
 2000 2500 3150 4000 5000 6300 8000 10000 12500 16000
20000


Download
thirtyone~.zip - object, help patch, source code

Source
//------------------------------------------------------------------------------
//  31 Band 1/3 Octave Equalizer For Pd
//
//  thirtyone~.c
//
//  Filters a signal through 31 evenly spaced
//  1/3 octave bandpass filters with gain
//
//  Created by Cooper Baker on 10/29/14.
//  Copyright (c) 2014 Cooper Baker. All rights reserved.
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
// headers
//------------------------------------------------------------------------------

// main header for pd
#include "m_pd.h"

// utility header for Pd Spectral Toolkit project
#include "utility.h"

// math header for fancy math
#include <math.h>

// stdio for debugging
#include <stdio.h>

// disable compiler warnings on windows
#ifdef NT
#pragma warning( disable : 4244 )
#pragma warning( disable : 4305 )
#endif

//------------------------------------------------------------------------------
// definitions
//------------------------------------------------------------------------------
#define NUM_BANDS 31

//------------------------------------------------------------------------------
// thirtyone_class - pointer to this object's definition
//------------------------------------------------------------------------------
static t_class* thirtyone_class;


//------------------------------------------------------------------------------
// thirtyone - data structure holding this object's data
//------------------------------------------------------------------------------
typedef struct thirtyone
{
    // this object - must always be first variable in struct
    t_object object;
   
    // needed for CLASS_MAINSIGNALIN macro call in thirtyone_tilde_setup
    t_float inlet_1;
   
    // coefficients for all filters
    double* b0;
    double* b1;
    double* b2;
    double* a1;
    double* a2;
   
    // sample memory for all filters
    double* x1;
    double* x2;
    double* y1;
    double* y2;
   
    // gains for all filters
    t_float* gains;
   
    // center frequencies for all filters
    t_float* centers;
   
    // sample rate
    t_float sr;
   
    // filter bandwidth
    t_float bw;
   
    // temp buffer
    t_float* temp;
   
} t_thirtyone;


//------------------------------------------------------------------------------
// function prototypes
//------------------------------------------------------------------------------
static void   thirtyone_messages    ( t_thirtyone* object, t_symbol* selector, t_int items, t_atom* list );
static void   thirtyone_calc_coeffs ( t_thirtyone* object );
static t_int* thirtyone_perform     ( t_int* io );
static void   thirtyone_dsp         ( t_thirtyone* object, t_signal **sig );
static void*  thirtyone_new         ( t_symbol* selector, t_int items, t_atom* list );
static void   thirtyone_free        ( t_thirtyone* object );
void          thirtyone_tilde_setup ( void );


//------------------------------------------------------------------------------
// thirtyone_calc_coeffs - calculates filter coefficients for each band
//
//      Adapted From:
//      Cookbook formulae for audio EQ biquad filter coefficients
//      By Robert Bristow-Johnson
//      http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
//
//------------------------------------------------------------------------------
static void thirtyone_calc_coeffs( t_thirtyone* object )
{
    double w0 = 0;
    double sin_w0 = 0;
    double alpha = 0;
    t_float bw = object->bw;
    t_float sr = object->sr;
    t_float a0 = 0;
   
    t_int i = 0;
   
    // calculate coefficients for each band
    for( i = 0 ; i < NUM_BANDS ; ++i )
    {
        // calculate intermediate values
        w0     = C_2_PI * object->centers[ i ] / sr;
        sin_w0 = sin( w0 );
        alpha  = sin_w0 * sinh( log( 2.0 ) / 2.0 * bw * w0 / sin_w0 );
       
        // calculate normalization coefficient
        a0 = ( 1.0 + alpha );

        // calculate filter coefficients for this band
        object->b0[ i ] = (  alpha           ) / a0;
        object->b1[ i ] = (  0.0             ) / a0;
        object->b2[ i ] = ( -alpha           ) / a0;
        object->a1[ i ] = ( -2.0 * cos( w0 ) ) / a0;
        object->a2[ i ] = (  1 - alpha       ) / a0;
    }
}


//------------------------------------------------------------------------------
// thirtyone_perform - the signal processing function of this object
//------------------------------------------------------------------------------
static t_int* thirtyone_perform( t_int* io )
{
    // store variables from dsp input/output array
    t_float*     in     = ( t_float*     )( io[ 1 ] );
    t_float*     out    = ( t_float*     )( io[ 2 ] );
    t_int        frames = ( t_int        )( io[ 3 ] );
    t_thirtyone* object = ( t_thirtyone* )( io[ 4 ] );
   
    // copy pointers to local variables
    t_float* temp = object->temp;
    double* b0    = object->b0;
    double* b1    = object->b1;
    double* b2    = object->b2;
    double* a1    = object->a1;
    double* a2    = object->a2;
    double* x1    = object->x1;
    double* x2    = object->x2;
    double* y1    = object->y1;
    double* y2    = object->y2;
    t_float* g    = object->gains;
   
    // filter iterator variable
    t_int i = -1;
 
    // signal vector iterator variable
    t_int n;

    // temporary sample variables
    double x = 0;
    double y = 0;
   
    // clear temp buffer
    memset( temp, 0, frames * sizeof( t_float ) );
   
    // iterate through the bands
    while( ++i < NUM_BANDS )
    {
        // reset vector iterator
        n = -1;
       
        // filter the input samples for each band
        while( ++n < frames )
        {
            // store input sample
            x = in[ n ];
           
            // direct form I biquad filter
            y = b0[i] * x + b1[i] * x1[i] + b2[i] * x2[i] - a1[i] * y1[i] - a2[i] * y2[i];

            // store previous input samples
            x2[i] = x1[i];
            x1[i] = x;
           
            // store previous output samples
            y2[i] = y1[i];
            y1[i] = y;
           
            // scale output by gain coefficient and mix into temp buffer
            temp[ n ] += y * g[ i ];
        }
    }

    // copy temp buffer of filtered bands to output
    memcpy( out, temp, frames * sizeof( t_float ) );

    // return the dsp input/output array address plus one more than its size
    // to provide a pointer to the next perform function in pd's call list
    return &( io[ 5 ] );
}


//------------------------------------------------------------------------------
// thirtyone_dsp - installs this object's dsp function in pd's callback list
//------------------------------------------------------------------------------
static void thirtyone_dsp( t_thirtyone* object, t_signal **sig )
{
    // store sample rate
    object->sr = sig[ 0 ]->s_sr;
   
    // allocate temporary audio buffer
    object->temp = realloc( object->temp, sig[ 0 ]->s_n * sizeof( t_float ) );
   
    // calculate coefficients
    thirtyone_calc_coeffs( object );
   
    // dsp_add arguments
    //--------------------------------------------------------------------------
    // perform routine
    // number of passed parameters
    // inlet sample vector
    // outlet sample vector
    // sample frames to process (vector size)
    // object pointer
    dsp_add( thirtyone_perform, 4, sig[ 0 ]->s_vec, sig[ 1 ]->s_vec, sig[ 0 ]->s_n, object );
}


//------------------------------------------------------------------------------
// thirtyone_messages - parses messages
//------------------------------------------------------------------------------
static void thirtyone_messages( t_thirtyone* object, t_symbol* selector, t_int items, t_atom* list )
{
    if( StringMatch( selector->s_name, "list" ) )
    {
        if( items == 2 )
        {
            if( ( list[ 0 ].a_type == A_FLOAT ) && ( list[ 1 ].a_type == A_FLOAT ) )
            {
                t_int   index   = list[ 0 ].a_w.w_float;
                t_float db_gain = list[ 1 ].a_w.w_float;
               
                index = Clip( index, 0, NUM_BANDS - 1 );
               
                object->gains[ index ] = DbToA( db_gain );
            }
            else
            {
                pd_error( object, "thirtyone~: invalid message" );
            }
        }
        else if( items == NUM_BANDS )
        {
            int valid = 1;
            int i = 0;

            for( i = 0 ; i < NUM_BANDS ; ++i )
            {
                if( list[ i ].a_type != A_FLOAT )
                {
                    valid = 0;
                    break;
                }
            }
           
            if( valid )
            {
                t_float db_gain = 0;
               
                for( i = 0 ; i < NUM_BANDS ; ++i )
                {
                    db_gain = list[ i ].a_w.w_float;
                    object->gains[ i ] = DbToA( db_gain );
                }
            }
            else
            {
                pd_error( object, "thirtyone~: invalid message" );
            }
        }
        else
        {
            pd_error( object, "thirtyone~: invalid message" );
        }

    }
    else if( StringMatch( selector->s_name, "reset" ) )
    {
        int i = 0;
       
        for( i = 0 ; i < NUM_BANDS ; ++i )
        {
            object->gains[ i ] = 1;
        }
    }
    else
    {
        pd_error( object, "thirtyone~: invalid message" );
    }
}


//------------------------------------------------------------------------------
// thirtyone_new - instantiates a copy of this object in pd
//------------------------------------------------------------------------------
static void* thirtyone_new( t_symbol* selector, t_int items, t_atom* list )
{
    // create a pointer to this object
    t_thirtyone* object = ( t_thirtyone* )pd_new( thirtyone_class );
   
    // create a new signal outlet for this object
    outlet_new( &object->object, gensym( "signal" ) );
   
    // set bandwidth of filters
    object->bw = 1.0 / 3.0;
   
    // set pointers to null
    object->b0      = NULL;
    object->b1      = NULL;
    object->b2      = NULL;
    object->a1      = NULL;
    object->a2      = NULL;
    object->gains   = NULL;
    object->centers = NULL;
    object->temp    = NULL;

    // allocate memory for filter parameters
    object->b0      = malloc( NUM_BANDS * sizeof( double  ) );
    object->b1      = malloc( NUM_BANDS * sizeof( double  ) );
    object->b2      = malloc( NUM_BANDS * sizeof( double  ) );
    object->a1      = malloc( NUM_BANDS * sizeof( double  ) );
    object->a2      = malloc( NUM_BANDS * sizeof( double  ) );
    object->x1      = malloc( NUM_BANDS * sizeof( double  ) );
    object->x2      = malloc( NUM_BANDS * sizeof( double  ) );
    object->y1      = malloc( NUM_BANDS * sizeof( double  ) );
    object->y2      = malloc( NUM_BANDS * sizeof( double  ) );
    object->gains   = malloc( NUM_BANDS * sizeof( t_float ) );
    object->centers = malloc( NUM_BANDS * sizeof( t_float ) );
   
    // set memory of filters to zero
    memset( object->x1, 0, NUM_BANDS * sizeof( double ) );
    memset( object->x2, 0, NUM_BANDS * sizeof( double ) );
    memset( object->y1, 0, NUM_BANDS * sizeof( double ) );
    memset( object->y2, 0, NUM_BANDS * sizeof( double ) );

    // initialize centers and gains
    t_int i = 0;
    t_float freq = 20;

    for( i = 0 ; i < NUM_BANDS ; ++i )
    {
        // printf( "%5.1f\n", freq );
       
        // 1/3 octave spacing
        object->centers[ i ] = freq;
        freq = freq * powf( 2.0, ( 1.0 / 3.0 ) );
       
        // unity gain ( 0 dB )
        object->gains[ i ] = 1;
    }
   
    // parse creation arguments
    if( items == NUM_BANDS )
    {
        int valid = 1;
        int i = 0;
       
        for( i = 0 ; i < NUM_BANDS ; ++i )
        {
            if( list[ i ].a_type != A_FLOAT )
            {
                valid = 0;
                break;
            }
        }

        if( valid )
        {
            t_float db_gain = 0;
           
            for( i = 0 ; i < NUM_BANDS ; ++i )
            {
                db_gain = list[ i ].a_w.w_float;
                object->gains[ i ] = DbToA( db_gain );
            }
        }
        else
        {
            pd_error( object, "thirtyone~: invalid initialization arguments" );
        }
    }
   
    return object;
}


//------------------------------------------------------------------------------
// thirtyone_free - cleans up memory allocated by this object
//------------------------------------------------------------------------------
static void thirtyone_free( t_thirtyone* object )
{
    // if memory is allocated
    if( object->b0 )
    {
        // free the memory
        free( object->b0 );

        // set memory pointer to null
        object->b0 = NULL;
    }
   
    // . . .
    if( object->b1 )
    {
        free( object->b1 );
        object->b1 = NULL;
    }

    if( object->b2 )
    {
        free( object->b2 );
        object->b2 = NULL;
    }

    if( object->a1 )
    {
        free( object->a1 );
        object->a1 = NULL;
    }

    if( object->a2 )
    {
        free( object->a2 );
        object->a2 = NULL;
    }
   
    if( object->x1 )
    {
        free( object->x1 );
        object->x1 = NULL;
    }
   
    if( object->x2 )
    {
        free( object->x2 );
        object->x2 = NULL;
    }
   
    if( object->y1 )
    {
        free( object->y1 );
        object->y1 = NULL;
    }
   
    if( object->y2 )
    {
        free( object->y2 );
        object->y2 = NULL;
    }
   
    if( object->gains )
    {
        free( object->gains );
        object->gains = NULL;
    }
   
    if( object->centers )
    {
        free( object->centers );
        object->centers = NULL;
    }
   
    if( object->temp )
    {
        free( object->temp );
        object->temp = NULL;
    }
}


//------------------------------------------------------------------------------
// thirtyone_tilde_setup - describes the attributes of this object to pd so it may be properly instantiated
// (must always be named with _tilde replacing ~ in the object name)
//------------------------------------------------------------------------------
void thirtyone_tilde_setup( void )
{
    // creates an instance of this object and describes it to pd
    thirtyone_class = class_new( gensym( "thirtyone~" ), ( t_newmethod )thirtyone_new, ( t_method )thirtyone_free, sizeof( t_thirtyone ), 0, A_GIMME, 0 );
   
    // declares leftmost inlet as a signal inlet
    CLASS_MAINSIGNALIN( thirtyone_class, t_thirtyone, inlet_1 );
   
    // installs thirtyone_dsp so that it will be called when dsp is turned on
    class_addmethod( thirtyone_class, ( t_method )thirtyone_dsp, gensym( "dsp" ), 0 );
   
    // installs thirtyone_set to respond to "set ___" messages
    class_addmethod( thirtyone_class, ( t_method )thirtyone_messages, gensym( "anything" ), A_GIMME, 0 );
   
    // announce this object in the pd console
    Announce( "thirtyone~: 31 band 1/3 octave equalizer - v1.0" );
}


//------------------------------------------------------------------------------
// EOF
//------------------------------------------------------------------------------